Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-153.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 156652 objects.
Mean distance to the closest unit in the map: 0.842.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_semana_2k.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt          tmax       
 Length:156652      Length:156652      Min.   : 1.00   Min.   :-109.0  
 Class :character   Class :character   1st Qu.:13.00   1st Qu.: 147.0  
 Mode  :character   Mode  :character   Median :27.00   Median : 201.0  
                                       Mean   :26.53   Mean   : 202.1  
                                       3rd Qu.:40.00   3rd Qu.: 262.0  
                                       Max.   :53.00   Max.   : 442.0  
      tmin             precip           nevada    prof_nieve      
 Min.   :-189.00   Min.   :  0.00   Min.   :0   Min.   :   0.000  
 1st Qu.:  48.00   1st Qu.:  0.00   1st Qu.:0   1st Qu.:   0.000  
 Median :  98.00   Median :  3.00   Median :0   Median :   0.000  
 Mean   :  98.13   Mean   : 16.92   Mean   :0   Mean   :   0.604  
 3rd Qu.: 152.00   3rd Qu.: 20.00   3rd Qu.:0   3rd Qu.:   0.000  
 Max.   : 272.00   Max.   :690.00   Max.   :0   Max.   :1073.000  
    longitud        latitud           altitud      
 Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:39.01   1st Qu.: -4.850   1st Qu.:  44.0  
 Median :41.22   Median : -1.411   Median : 263.0  
 Mean   :40.05   Mean   : -2.426   Mean   : 478.5  
 3rd Qu.:42.19   3rd Qu.:  1.272   3rd Qu.: 687.0  
 Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

    1     2     3     4     5     6     7     8     9    10    11    12    13 
 1619 13034  5882  5349  9756  5410  6322  4469 12863  5599  8683  5130  4831 
   14    15    16    17    18    19    20    21    22    23    24    25 
 5970  5633  6703 10019  5514 12055  5335  2132  9150  3211  1527   456 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("fecha_cnt", "precip", "longitud", "latitud", "altitud")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
      fecha_cnt      precip   longitud    latitud   altitud
[1,] -0.4088161 -0.04241518 -0.6224200 -0.3070668 -0.567090
[2,] -0.6798965  0.25950245  0.4027636  0.2054039  0.452923

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
 longitud   latitud    precip   altitud fecha_cnt 
0.9656268 0.9375270 0.9009239 0.8723928 0.8629843 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip      
 Min.   : 1.00   Min.   :-109.0   Min.   :-189.00   Min.   :  0.00  
 1st Qu.:13.00   1st Qu.: 144.0   1st Qu.:  45.00   1st Qu.:  0.00  
 Median :27.00   Median : 196.0   Median :  93.00   Median :  4.00  
 Mean   :26.53   Mean   : 200.4   Mean   :  93.73   Mean   : 16.87  
 3rd Qu.:40.00   3rd Qu.: 262.0   3rd Qu.: 145.00   3rd Qu.: 22.00  
 Max.   :53.00   Max.   : 442.0   Max.   : 272.00   Max.   :223.00  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.88   1st Qu.: -4.049  
 Median :0   Median :   0.0000   Median :41.38   Median : -1.033  
 Mean   :0   Mean   :   0.6289   Mean   :40.83   Mean   : -1.519  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.24   3rd Qu.:  1.363  
 Max.   :0   Max.   :1073.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  58.0  
 Median : 316.0  
 Mean   : 485.1  
 3rd Qu.: 704.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt         tmax            tmin           precip            nevada 
 Min.   : 1.0   Min.   :  1.0   Min.   :-51.0   Min.   :  0.000   Min.   :0  
 1st Qu.:13.0   1st Qu.:211.0   1st Qu.:149.0   1st Qu.:  0.000   1st Qu.:0  
 Median :26.0   Median :234.0   Median :172.0   Median :  0.000   Median :0  
 Mean   :26.3   Mean   :229.7   Mean   :165.3   Mean   :  5.343   Mean   :0  
 3rd Qu.:39.0   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  2.000   3rd Qu.:0  
 Max.   :53.0   Max.   :384.0   Max.   :263.0   Max.   :155.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25.0  
 Median :0    Median :28.44   Median :-16.33   Median :  33.0  
 Mean   :0    Mean   :28.35   Mean   :-16.03   Mean   : 369.2  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64.0  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.00   Min.   :193.0   Min.   :0  
 1st Qu.:10.00   1st Qu.:102.0   1st Qu.:  42.00   1st Qu.:233.0   1st Qu.:0  
 Median :40.00   Median :139.0   Median :  80.50   Median :256.5   Median :0  
 Mean   :29.92   Mean   :135.9   Mean   :  73.51   Mean   :282.0   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:182.2   3rd Qu.: 117.00   3rd Qu.:309.2   3rd Qu.:0  
 Max.   :53.00   Max.   :331.0   Max.   : 217.00   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.742   1st Qu.:  66.7  
 Median :  0.000   Median :42.12   Median : -1.033   Median : 261.0  
 Mean   :  5.531   Mean   :40.78   Mean   : -2.630   Mean   : 696.9  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.168   3rd Qu.:1055.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax          tmin            precip           nevada 
 Min.   : 1.00   Min.   :-43   Min.   :-80.00   Min.   : 25.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:135   1st Qu.: 56.00   1st Qu.: 50.00   1st Qu.:0  
 Median :22.00   Median :170   Median : 87.00   Median : 65.00   Median :0  
 Mean   :25.97   Mean   :175   Mean   : 88.62   Mean   : 75.76   Mean   :0  
 3rd Qu.:42.00   3rd Qu.:211   3rd Qu.:120.00   3rd Qu.: 91.00   3rd Qu.:0  
 Max.   :53.00   Max.   :407   Max.   :247.00   Max.   :223.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.95   1st Qu.: -4.846   1st Qu.:  58.0  
 Median :  0.0000   Median :41.84   Median : -1.636   Median : 252.0  
 Mean   :  0.3992   Mean   :41.47   Mean   : -1.781   Mean   : 340.2  
 3rd Qu.:  0.0000   3rd Qu.:42.70   3rd Qu.:  1.521   3rd Qu.: 541.0  
 Max.   :907.0000   Max.   :43.57   Max.   :  4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt         tmax             tmin             precip       
 Min.   : 1.0   Min.   :-109.0   Min.   :-189.00   Min.   :  0.000  
 1st Qu.:14.0   1st Qu.: 146.0   1st Qu.:  43.00   1st Qu.:  0.000  
 Median :27.0   Median : 202.0   Median :  95.00   Median :  2.000  
 Mean   :26.6   Mean   : 203.7   Mean   :  94.39   Mean   :  9.227  
 3rd Qu.:39.0   3rd Qu.: 269.0   3rd Qu.: 149.00   3rd Qu.: 13.000  
 Max.   :53.0   Max.   : 442.0   Max.   : 272.00   Max.   :200.000  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :28.31   Min.   :-16.499  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.56   1st Qu.: -4.010  
 Median :0   Median :   0.0000   Median :41.31   Median : -1.033  
 Mean   :0   Mean   :   0.6587   Mean   :40.75   Mean   : -1.485  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.18   3rd Qu.:  1.363  
 Max.   :0   Max.   :1073.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  58.0  
 Median : 336.0  
 Mean   : 503.9  
 3rd Qu.: 735.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt         tmax            tmin           precip            nevada 
 Min.   : 1.0   Min.   :  1.0   Min.   :-51.0   Min.   :  0.000   Min.   :0  
 1st Qu.:13.0   1st Qu.:211.0   1st Qu.:149.0   1st Qu.:  0.000   1st Qu.:0  
 Median :26.0   Median :234.0   Median :172.0   Median :  0.000   Median :0  
 Mean   :26.3   Mean   :229.7   Mean   :165.3   Mean   :  5.343   Mean   :0  
 3rd Qu.:39.0   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  2.000   3rd Qu.:0  
 Max.   :53.0   Max.   :384.0   Max.   :263.0   Max.   :155.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25.0  
 Median :0    Median :28.44   Median :-16.33   Median :  33.0  
 Mean   :0    Mean   :28.35   Mean   :-16.03   Mean   : 369.2  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64.0  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.00   Min.   :193.0   Min.   :0  
 1st Qu.:10.00   1st Qu.:102.0   1st Qu.:  42.00   1st Qu.:233.0   1st Qu.:0  
 Median :40.00   Median :139.0   Median :  80.50   Median :256.5   Median :0  
 Mean   :29.92   Mean   :135.9   Mean   :  73.51   Mean   :282.0   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:182.2   3rd Qu.: 117.00   3rd Qu.:309.2   3rd Qu.:0  
 Max.   :53.00   Max.   :331.0   Max.   : 217.00   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.742   1st Qu.:  66.7  
 Median :  0.000   Median :42.12   Median : -1.033   Median : 261.0  
 Mean   :  5.531   Mean   :40.78   Mean   : -2.630   Mean   : 696.9  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.168   3rd Qu.:1055.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax          tmin            precip           nevada 
 Min.   : 1.00   Min.   :-43   Min.   :-80.00   Min.   : 25.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:135   1st Qu.: 56.00   1st Qu.: 50.00   1st Qu.:0  
 Median :22.00   Median :170   Median : 87.00   Median : 65.00   Median :0  
 Mean   :25.97   Mean   :175   Mean   : 88.62   Mean   : 75.76   Mean   :0  
 3rd Qu.:42.00   3rd Qu.:211   3rd Qu.:120.00   3rd Qu.: 91.00   3rd Qu.:0  
 Max.   :53.00   Max.   :407   Max.   :247.00   Max.   :223.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.95   1st Qu.: -4.846   1st Qu.:  58.0  
 Median :  0.0000   Median :41.84   Median : -1.636   Median : 252.0  
 Mean   :  0.3992   Mean   :41.47   Mean   : -1.781   Mean   : 340.2  
 3rd Qu.:  0.0000   3rd Qu.:42.70   3rd Qu.:  1.521   3rd Qu.: 541.0  
 Max.   :907.0000   Max.   :43.57   Max.   :  4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   : 1.00   Min.   :-35.0   Min.   :-189.0   Min.   : 0.000   Min.   :0  
 1st Qu.:14.00   1st Qu.:155.0   1st Qu.:  50.0   1st Qu.: 0.000   1st Qu.:0  
 Median :27.00   Median :209.0   Median : 101.0   Median : 2.000   Median :0  
 Mean   :26.61   Mean   :212.5   Mean   : 100.3   Mean   : 7.496   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:273.0   3rd Qu.: 152.0   3rd Qu.:12.000   3rd Qu.:0  
 Max.   :53.00   Max.   :442.0   Max.   : 272.0   Max.   :65.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :  0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:39.49   1st Qu.:-4.127   1st Qu.:  52.0  
 Median :  0.0000   Median :41.17   Median :-1.229   Median : 261.0  
 Mean   :  0.1024   Mean   :40.64   Mean   :-1.647   Mean   : 379.5  
 3rd Qu.:  0.0000   3rd Qu.:42.05   3rd Qu.: 1.201   3rd Qu.: 656.0  
 Max.   :757.0000   Max.   :43.57   Max.   : 4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt         tmax            tmin           precip            nevada 
 Min.   : 1.0   Min.   :  1.0   Min.   :-51.0   Min.   :  0.000   Min.   :0  
 1st Qu.:13.0   1st Qu.:211.0   1st Qu.:149.0   1st Qu.:  0.000   1st Qu.:0  
 Median :26.0   Median :234.0   Median :172.0   Median :  0.000   Median :0  
 Mean   :26.3   Mean   :229.7   Mean   :165.3   Mean   :  5.343   Mean   :0  
 3rd Qu.:39.0   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  2.000   3rd Qu.:0  
 Max.   :53.0   Max.   :384.0   Max.   :263.0   Max.   :155.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25.0  
 Median :0    Median :28.44   Median :-16.33   Median :  33.0  
 Mean   :0    Mean   :28.35   Mean   :-16.03   Mean   : 369.2  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64.0  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax              tmin             precip      
 Min.   : 1.00   Min.   :-109.00   Min.   :-175.00   Min.   :  0.00  
 1st Qu.:14.00   1st Qu.:  28.00   1st Qu.: -34.00   1st Qu.:  4.00  
 Median :27.00   Median :  78.00   Median :  10.00   Median : 20.00  
 Mean   :26.56   Mean   :  83.96   Mean   :  13.55   Mean   : 32.89  
 3rd Qu.:39.00   3rd Qu.: 139.00   3rd Qu.:  64.00   3rd Qu.: 50.00  
 Max.   :53.00   Max.   : 299.00   Max.   : 183.00   Max.   :200.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.29   1st Qu.:  0.7789  
 Median :0   Median :   0.000   Median :42.47   Median :  1.0544  
 Mean   :0   Mean   :   8.264   Mean   :42.27   Mean   :  0.7201  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.7150  
 Max.   :0   Max.   :1073.000   Max.   :42.77   Max.   :  2.4378  
    altitud    
 Min.   :1097  
 1st Qu.:1971  
 Median :2247  
 Mean   :2204  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.00   Min.   :193.0   Min.   :0  
 1st Qu.:10.00   1st Qu.:102.0   1st Qu.:  42.00   1st Qu.:233.0   1st Qu.:0  
 Median :40.00   Median :139.0   Median :  80.50   Median :256.5   Median :0  
 Mean   :29.92   Mean   :135.9   Mean   :  73.51   Mean   :282.0   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:182.2   3rd Qu.: 117.00   3rd Qu.:309.2   3rd Qu.:0  
 Max.   :53.00   Max.   :331.0   Max.   : 217.00   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.742   1st Qu.:  66.7  
 Median :  0.000   Median :42.12   Median : -1.033   Median : 261.0  
 Mean   :  5.531   Mean   :40.78   Mean   : -2.630   Mean   : 696.9  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.168   3rd Qu.:1055.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax          tmin            precip           nevada 
 Min.   : 1.00   Min.   :-43   Min.   :-80.00   Min.   : 25.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:135   1st Qu.: 56.00   1st Qu.: 50.00   1st Qu.:0  
 Median :22.00   Median :170   Median : 87.00   Median : 65.00   Median :0  
 Mean   :25.97   Mean   :175   Mean   : 88.62   Mean   : 75.76   Mean   :0  
 3rd Qu.:42.00   3rd Qu.:211   3rd Qu.:120.00   3rd Qu.: 91.00   3rd Qu.:0  
 Max.   :53.00   Max.   :407   Max.   :247.00   Max.   :223.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.95   1st Qu.: -4.846   1st Qu.:  58.0  
 Median :  0.0000   Median :41.84   Median : -1.636   Median : 252.0  
 Mean   :  0.3992   Mean   :41.47   Mean   : -1.781   Mean   : 340.2  
 3rd Qu.:  0.0000   3rd Qu.:42.70   3rd Qu.:  1.521   3rd Qu.: 541.0  
 Max.   :907.0000   Max.   :43.57   Max.   :  4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin          precip           nevada 
 Min.   : 1.00   Min.   :-35.0   Min.   :-155   Min.   : 0.000   Min.   :0  
 1st Qu.:24.00   1st Qu.:176.0   1st Qu.:  76   1st Qu.: 0.000   1st Qu.:0  
 Median :33.00   Median :238.0   Median : 124   Median : 1.000   Median :0  
 Mean   :32.77   Mean   :231.9   Mean   : 119   Mean   : 7.454   Mean   :0  
 3rd Qu.:43.00   3rd Qu.:290.0   3rd Qu.: 166   3rd Qu.:11.000   3rd Qu.:0  
 Max.   :53.00   Max.   :442.0   Max.   : 272   Max.   :65.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :  0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:38.99   1st Qu.:-5.498   1st Qu.:  44.0  
 Median :  0.0000   Median :41.15   Median :-2.138   Median : 196.0  
 Mean   :  0.0811   Mean   :40.55   Mean   :-2.157   Mean   : 350.2  
 3rd Qu.:  0.0000   3rd Qu.:42.12   3rd Qu.: 1.026   3rd Qu.: 611.0  
 Max.   :757.0000   Max.   :43.57   Max.   : 4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt         tmax            tmin           precip            nevada 
 Min.   : 1.0   Min.   :  1.0   Min.   :-51.0   Min.   :  0.000   Min.   :0  
 1st Qu.:13.0   1st Qu.:211.0   1st Qu.:149.0   1st Qu.:  0.000   1st Qu.:0  
 Median :26.0   Median :234.0   Median :172.0   Median :  0.000   Median :0  
 Mean   :26.3   Mean   :229.7   Mean   :165.3   Mean   :  5.343   Mean   :0  
 3rd Qu.:39.0   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  2.000   3rd Qu.:0  
 Max.   :53.0   Max.   :384.0   Max.   :263.0   Max.   :155.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25.0  
 Median :0    Median :28.44   Median :-16.33   Median :  33.0  
 Mean   :0    Mean   :28.35   Mean   :-16.03   Mean   : 369.2  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64.0  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin          precip           nevada 
 Min.   : 1.000   Min.   :-26.0   Min.   :-189   Min.   : 0.000   Min.   :0  
 1st Qu.: 5.000   1st Qu.:124.0   1st Qu.:  16   1st Qu.: 0.000   1st Qu.:0  
 Median : 9.000   Median :159.0   Median :  47   Median : 3.000   Median :0  
 Mean   : 9.986   Mean   :160.2   Mean   :  50   Mean   : 7.608   Mean   :0  
 3rd Qu.:14.000   3rd Qu.:194.0   3rd Qu.:  81   3rd Qu.:12.000   3rd Qu.:0  
 Max.   :26.000   Max.   :368.0   Max.   : 243   Max.   :57.000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :36.85   Min.   :-5.7333   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.30   1st Qu.:-1.8853   1st Qu.:  69.0  
 Median :  0.0000   Median :41.19   Median : 0.5356   Median : 427.0  
 Mean   :  0.1599   Mean   :40.87   Mean   :-0.2711   Mean   : 458.5  
 3rd Qu.:  0.0000   3rd Qu.:41.84   3rd Qu.: 1.6331   3rd Qu.: 785.0  
 Max.   :458.0000   Max.   :43.36   Max.   : 4.2156   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax              tmin             precip      
 Min.   : 1.00   Min.   :-109.00   Min.   :-175.00   Min.   :  0.00  
 1st Qu.:14.00   1st Qu.:  28.00   1st Qu.: -34.00   1st Qu.:  4.00  
 Median :27.00   Median :  78.00   Median :  10.00   Median : 20.00  
 Mean   :26.56   Mean   :  83.96   Mean   :  13.55   Mean   : 32.89  
 3rd Qu.:39.00   3rd Qu.: 139.00   3rd Qu.:  64.00   3rd Qu.: 50.00  
 Max.   :53.00   Max.   : 299.00   Max.   : 183.00   Max.   :200.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.29   1st Qu.:  0.7789  
 Median :0   Median :   0.000   Median :42.47   Median :  1.0544  
 Mean   :0   Mean   :   8.264   Mean   :42.27   Mean   :  0.7201  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.7150  
 Max.   :0   Max.   :1073.000   Max.   :42.77   Max.   :  2.4378  
    altitud    
 Min.   :1097  
 1st Qu.:1971  
 Median :2247  
 Mean   :2204  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.00   Min.   :193.0   Min.   :0  
 1st Qu.:10.00   1st Qu.:102.0   1st Qu.:  42.00   1st Qu.:233.0   1st Qu.:0  
 Median :40.00   Median :139.0   Median :  80.50   Median :256.5   Median :0  
 Mean   :29.92   Mean   :135.9   Mean   :  73.51   Mean   :282.0   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:182.2   3rd Qu.: 117.00   3rd Qu.:309.2   3rd Qu.:0  
 Max.   :53.00   Max.   :331.0   Max.   : 217.00   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.742   1st Qu.:  66.7  
 Median :  0.000   Median :42.12   Median : -1.033   Median : 261.0  
 Mean   :  5.531   Mean   :40.78   Mean   : -2.630   Mean   : 696.9  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.168   3rd Qu.:1055.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin           precip          nevada 
 Min.   : 1.00   Min.   :-43.0   Min.   :-76.0   Min.   : 92.0   Min.   :0  
 1st Qu.:12.00   1st Qu.:130.0   1st Qu.: 61.0   1st Qu.:113.0   1st Qu.:0  
 Median :34.00   Median :162.0   Median : 88.0   Median :129.0   Median :0  
 Mean   :28.69   Mean   :164.9   Mean   : 89.7   Mean   :136.7   Mean   :0  
 3rd Qu.:45.00   3rd Qu.:196.0   3rd Qu.:119.0   3rd Qu.:156.0   3rd Qu.:0  
 Max.   :53.00   Max.   :407.0   Max.   :228.0   Max.   :223.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:41.06   1st Qu.: -5.733   1st Qu.:  43.3  
 Median :  0.000   Median :41.98   Median : -1.787   Median : 150.0  
 Mean   :  1.628   Mean   :41.40   Mean   : -2.129   Mean   : 297.4  
 3rd Qu.:  0.000   3rd Qu.:42.87   3rd Qu.:  1.768   3rd Qu.: 421.0  
 Max.   :907.000   Max.   :43.57   Max.   :  4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   : 1.00   Min.   :-35.0   Min.   :-155.0   Min.   : 0.000   Min.   :0  
 1st Qu.:26.00   1st Qu.:174.0   1st Qu.:  73.0   1st Qu.: 0.000   1st Qu.:0  
 Median :34.00   Median :240.0   Median : 123.0   Median : 2.000   Median :0  
 Mean   :34.29   Mean   :230.8   Mean   : 116.6   Mean   : 7.549   Mean   :0  
 3rd Qu.:44.00   3rd Qu.:290.0   3rd Qu.: 164.0   3rd Qu.:12.000   3rd Qu.:0  
 Max.   :53.00   Max.   :442.0   Max.   : 272.0   Max.   :64.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :  0.0000   Min.   :36.85   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.70   1st Qu.:-3.808   1st Qu.:  69.0  
 Median :  0.0000   Median :41.57   Median :-1.008   Median : 336.0  
 Mean   :  0.0992   Mean   :41.37   Mean   :-1.437   Mean   : 404.1  
 3rd Qu.:  0.0000   3rd Qu.:42.33   3rd Qu.: 1.384   3rd Qu.: 667.0  
 Max.   :757.0000   Max.   :43.57   Max.   : 4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   : 1.00   Min.   : 52.0   Min.   :-65.0   Min.   : 0.000   Min.   :0  
 1st Qu.:13.00   1st Qu.:180.0   1st Qu.: 86.0   1st Qu.: 0.000   1st Qu.:0  
 Median :26.00   Median :228.0   Median :130.0   Median : 0.000   Median :0  
 Mean   :26.25   Mean   :236.8   Mean   :129.4   Mean   : 7.046   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:289.0   3rd Qu.:177.0   3rd Qu.: 9.000   3rd Qu.:0  
 Max.   :53.00   Max.   :431.0   Max.   :269.0   Max.   :65.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud     
 Min.   :0.000000   Min.   :35.28   Min.   :-6.949   Min.   :  1.0  
 1st Qu.:0.000000   1st Qu.:36.64   1st Qu.:-6.257   1st Qu.: 21.0  
 Median :0.000000   Median :37.16   Median :-5.600   Median : 34.0  
 Mean   :0.003015   Mean   :37.02   Mean   :-5.261   Mean   :117.4  
 3rd Qu.:0.000000   3rd Qu.:37.42   3rd Qu.:-4.488   3rd Qu.: 90.0  
 Max.   :4.000000   Max.   :39.47   Max.   :-1.169   Max.   :582.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt         tmax            tmin           precip            nevada 
 Min.   : 1.0   Min.   :  1.0   Min.   :-51.0   Min.   :  0.000   Min.   :0  
 1st Qu.:13.0   1st Qu.:211.0   1st Qu.:149.0   1st Qu.:  0.000   1st Qu.:0  
 Median :26.0   Median :234.0   Median :172.0   Median :  0.000   Median :0  
 Mean   :26.3   Mean   :229.7   Mean   :165.3   Mean   :  5.343   Mean   :0  
 3rd Qu.:39.0   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  2.000   3rd Qu.:0  
 Max.   :53.0   Max.   :384.0   Max.   :263.0   Max.   :155.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25.0  
 Median :0    Median :28.44   Median :-16.33   Median :  33.0  
 Mean   :0    Mean   :28.35   Mean   :-16.03   Mean   : 369.2  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64.0  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   : 1.00   Min.   :  8.0   Min.   :-80.00   Min.   : 25.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:136.0   1st Qu.: 55.00   1st Qu.: 48.00   1st Qu.:0  
 Median :21.00   Median :173.0   Median : 86.00   Median : 59.00   Median :0  
 Mean   :25.35   Mean   :177.4   Mean   : 88.37   Mean   : 61.75   Mean   :0  
 3rd Qu.:41.00   3rd Qu.:215.0   3rd Qu.:121.00   3rd Qu.: 74.25   3rd Qu.:0  
 Max.   :53.00   Max.   :376.0   Max.   :247.00   Max.   :110.00   Max.   :0  
   prof_nieve         longitud        latitud          altitud    
 Min.   : 0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1  
 1st Qu.: 0.0000   1st Qu.:40.93   1st Qu.:-4.680   1st Qu.:  61  
 Median : 0.0000   Median :41.83   Median :-1.411   Median : 261  
 Mean   : 0.1166   Mean   :41.49   Mean   :-1.701   Mean   : 350  
 3rd Qu.: 0.0000   3rd Qu.:42.59   3rd Qu.: 1.512   3rd Qu.: 566  
 Max.   :93.0000   Max.   :43.57   Max.   : 4.216   Max.   :1405  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin          precip           nevada 
 Min.   : 1.000   Min.   :-26.0   Min.   :-189   Min.   : 0.000   Min.   :0  
 1st Qu.: 5.000   1st Qu.:124.0   1st Qu.:  16   1st Qu.: 0.000   1st Qu.:0  
 Median : 9.000   Median :159.0   Median :  47   Median : 3.000   Median :0  
 Mean   : 9.986   Mean   :160.2   Mean   :  50   Mean   : 7.608   Mean   :0  
 3rd Qu.:14.000   3rd Qu.:194.0   3rd Qu.:  81   3rd Qu.:12.000   3rd Qu.:0  
 Max.   :26.000   Max.   :368.0   Max.   : 243   Max.   :57.000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :36.85   Min.   :-5.7333   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.30   1st Qu.:-1.8853   1st Qu.:  69.0  
 Median :  0.0000   Median :41.19   Median : 0.5356   Median : 427.0  
 Mean   :  0.1599   Mean   :40.87   Mean   :-0.2711   Mean   : 458.5  
 3rd Qu.:  0.0000   3rd Qu.:41.84   3rd Qu.: 1.6331   3rd Qu.: 785.0  
 Max.   :458.0000   Max.   :43.36   Max.   : 4.2156   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax              tmin             precip      
 Min.   : 1.00   Min.   :-109.00   Min.   :-175.00   Min.   :  0.00  
 1st Qu.:14.00   1st Qu.:  28.00   1st Qu.: -34.00   1st Qu.:  4.00  
 Median :27.00   Median :  78.00   Median :  10.00   Median : 20.00  
 Mean   :26.56   Mean   :  83.96   Mean   :  13.55   Mean   : 32.89  
 3rd Qu.:39.00   3rd Qu.: 139.00   3rd Qu.:  64.00   3rd Qu.: 50.00  
 Max.   :53.00   Max.   : 299.00   Max.   : 183.00   Max.   :200.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.29   1st Qu.:  0.7789  
 Median :0   Median :   0.000   Median :42.47   Median :  1.0544  
 Mean   :0   Mean   :   8.264   Mean   :42.27   Mean   :  0.7201  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.7150  
 Max.   :0   Max.   :1073.000   Max.   :42.77   Max.   :  2.4378  
    altitud    
 Min.   :1097  
 1st Qu.:1971  
 Median :2247  
 Mean   :2204  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.00   Min.   :193.0   Min.   :0  
 1st Qu.:10.00   1st Qu.:102.0   1st Qu.:  42.00   1st Qu.:233.0   1st Qu.:0  
 Median :40.00   Median :139.0   Median :  80.50   Median :256.5   Median :0  
 Mean   :29.92   Mean   :135.9   Mean   :  73.51   Mean   :282.0   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:182.2   3rd Qu.: 117.00   3rd Qu.:309.2   3rd Qu.:0  
 Max.   :53.00   Max.   :331.0   Max.   : 217.00   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.742   1st Qu.:  66.7  
 Median :  0.000   Median :42.12   Median : -1.033   Median : 261.0  
 Mean   :  5.531   Mean   :40.78   Mean   : -2.630   Mean   : 696.9  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.168   3rd Qu.:1055.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin           precip          nevada 
 Min.   : 1.00   Min.   :-43.0   Min.   :-76.0   Min.   : 92.0   Min.   :0  
 1st Qu.:12.00   1st Qu.:130.0   1st Qu.: 61.0   1st Qu.:113.0   1st Qu.:0  
 Median :34.00   Median :162.0   Median : 88.0   Median :129.0   Median :0  
 Mean   :28.69   Mean   :164.9   Mean   : 89.7   Mean   :136.7   Mean   :0  
 3rd Qu.:45.00   3rd Qu.:196.0   3rd Qu.:119.0   3rd Qu.:156.0   3rd Qu.:0  
 Max.   :53.00   Max.   :407.0   Max.   :228.0   Max.   :223.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:41.06   1st Qu.: -5.733   1st Qu.:  43.3  
 Median :  0.000   Median :41.98   Median : -1.787   Median : 150.0  
 Mean   :  1.628   Mean   :41.40   Mean   : -2.129   Mean   : 297.4  
 3rd Qu.:  0.000   3rd Qu.:42.87   3rd Qu.:  1.768   3rd Qu.: 421.0  
 Max.   :907.000   Max.   :43.57   Max.   :  4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt         tmax            tmin            precip          nevada 
 Min.   :13.0   Min.   :-31.0   Min.   :-67.00   Min.   : 0.00   Min.   :0  
 1st Qu.:27.0   1st Qu.:195.0   1st Qu.: 93.75   1st Qu.: 0.00   1st Qu.:0  
 Median :35.0   Median :255.0   Median :145.00   Median : 1.00   Median :0  
 Mean   :35.3   Mean   :243.1   Mean   :135.32   Mean   : 6.14   Mean   :0  
 3rd Qu.:44.0   3rd Qu.:295.0   3rd Qu.:182.00   3rd Qu.: 9.00   3rd Qu.:0  
 Max.   :53.0   Max.   :442.0   Max.   :272.00   Max.   :51.00   Max.   :0  
   prof_nieve           longitud        latitud           altitud     
 Min.   :  0.00000   Min.   :36.85   Min.   :-6.0442   Min.   :  1.0  
 1st Qu.:  0.00000   1st Qu.:40.82   1st Qu.: 0.3056   1st Qu.: 32.0  
 Median :  0.00000   Median :41.43   Median : 0.8564   Median : 91.0  
 Mean   :  0.01134   Mean   :41.15   Mean   : 0.7660   Mean   :175.7  
 3rd Qu.:  0.00000   3rd Qu.:41.96   3rd Qu.: 2.0697   3rd Qu.:287.0  
 Max.   :290.00000   Max.   :43.57   Max.   : 4.2156   Max.   :691.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   : 1.00   Min.   : 52.0   Min.   :-65.0   Min.   : 0.000   Min.   :0  
 1st Qu.:13.00   1st Qu.:180.0   1st Qu.: 86.0   1st Qu.: 0.000   1st Qu.:0  
 Median :26.00   Median :228.0   Median :130.0   Median : 0.000   Median :0  
 Mean   :26.25   Mean   :236.8   Mean   :129.4   Mean   : 7.046   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:289.0   3rd Qu.:177.0   3rd Qu.: 9.000   3rd Qu.:0  
 Max.   :53.00   Max.   :431.0   Max.   :269.0   Max.   :65.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud     
 Min.   :0.000000   Min.   :35.28   Min.   :-6.949   Min.   :  1.0  
 1st Qu.:0.000000   1st Qu.:36.64   1st Qu.:-6.257   1st Qu.: 21.0  
 Median :0.000000   Median :37.16   Median :-5.600   Median : 34.0  
 Mean   :0.003015   Mean   :37.02   Mean   :-5.261   Mean   :117.4  
 3rd Qu.:0.000000   3rd Qu.:37.42   3rd Qu.:-4.488   3rd Qu.: 90.0  
 Max.   :4.000000   Max.   :39.47   Max.   :-1.169   Max.   :582.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt         tmax            tmin           precip            nevada 
 Min.   : 1.0   Min.   :  1.0   Min.   :-51.0   Min.   :  0.000   Min.   :0  
 1st Qu.:13.0   1st Qu.:211.0   1st Qu.:149.0   1st Qu.:  0.000   1st Qu.:0  
 Median :26.0   Median :234.0   Median :172.0   Median :  0.000   Median :0  
 Mean   :26.3   Mean   :229.7   Mean   :165.3   Mean   :  5.343   Mean   :0  
 3rd Qu.:39.0   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  2.000   3rd Qu.:0  
 Max.   :53.0   Max.   :384.0   Max.   :263.0   Max.   :155.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25.0  
 Median :0    Median :28.44   Median :-16.33   Median :  33.0  
 Mean   :0    Mean   :28.35   Mean   :-16.03   Mean   : 369.2  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64.0  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   : 1.00   Min.   : 40.0   Min.   :-68.00   Min.   : 0.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:151.0   1st Qu.: 67.00   1st Qu.: 1.00   1st Qu.:0  
 Median :27.00   Median :194.0   Median :102.00   Median : 8.00   Median :0  
 Mean   :26.15   Mean   :194.7   Mean   : 99.13   Mean   :12.35   Mean   :0  
 3rd Qu.:38.00   3rd Qu.:233.0   3rd Qu.:135.00   3rd Qu.:21.00   3rd Qu.:0  
 Max.   :53.00   Max.   :398.0   Max.   :207.00   Max.   :58.00   Max.   :0  
   prof_nieve           longitud        latitud          altitud   
 Min.   :  0.00000   Min.   :42.24   Min.   :-8.624   Min.   :  5  
 1st Qu.:  0.00000   1st Qu.:42.56   1st Qu.:-8.411   1st Qu.: 58  
 Median :  0.00000   Median :43.31   Median :-7.456   Median :127  
 Mean   :  0.05507   Mean   :43.04   Mean   :-7.001   Mean   :200  
 3rd Qu.:  0.00000   3rd Qu.:43.43   3rd Qu.:-5.873   3rd Qu.:336  
 Max.   :177.00000   Max.   :43.57   Max.   :-2.906   Max.   :534  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :17.00   Min.   :-35.0   Min.   :-155.0   Min.   : 0.000   Min.   :0  
 1st Qu.:28.00   1st Qu.:157.0   1st Qu.:  51.0   1st Qu.: 0.000   1st Qu.:0  
 Median :36.00   Median :243.0   Median : 104.0   Median : 2.000   Median :0  
 Mean   :36.15   Mean   :227.7   Mean   :  96.5   Mean   : 7.627   Mean   :0  
 3rd Qu.:44.00   3rd Qu.:297.0   3rd Qu.: 144.0   3rd Qu.:11.000   3rd Qu.:0  
 Max.   :53.00   Max.   :402.0   Max.   : 266.0   Max.   :64.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :  0.0000   Min.   :37.13   Min.   :-6.600   Min.   : 405.0  
 1st Qu.:  0.0000   1st Qu.:40.38   1st Qu.:-4.049   1st Qu.: 656.0  
 Median :  0.0000   Median :40.95   Median :-3.450   Median : 788.0  
 Mean   :  0.2444   Mean   :41.00   Mean   :-2.352   Mean   : 818.5  
 3rd Qu.:  0.0000   3rd Qu.:41.84   3rd Qu.:-1.117   3rd Qu.: 945.0  
 Max.   :757.0000   Max.   :42.87   Max.   : 2.438   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   : 1.00   Min.   :  8.0   Min.   :-80.00   Min.   : 25.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:136.0   1st Qu.: 55.00   1st Qu.: 48.00   1st Qu.:0  
 Median :21.00   Median :173.0   Median : 86.00   Median : 59.00   Median :0  
 Mean   :25.35   Mean   :177.4   Mean   : 88.37   Mean   : 61.75   Mean   :0  
 3rd Qu.:41.00   3rd Qu.:215.0   3rd Qu.:121.00   3rd Qu.: 74.25   3rd Qu.:0  
 Max.   :53.00   Max.   :376.0   Max.   :247.00   Max.   :110.00   Max.   :0  
   prof_nieve         longitud        latitud          altitud    
 Min.   : 0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1  
 1st Qu.: 0.0000   1st Qu.:40.93   1st Qu.:-4.680   1st Qu.:  61  
 Median : 0.0000   Median :41.83   Median :-1.411   Median : 261  
 Mean   : 0.1166   Mean   :41.49   Mean   :-1.701   Mean   : 350  
 3rd Qu.: 0.0000   3rd Qu.:42.59   3rd Qu.: 1.512   3rd Qu.: 566  
 Max.   :93.0000   Max.   :43.57   Max.   : 4.216   Max.   :1405  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin          precip           nevada 
 Min.   : 1.000   Min.   :-26.0   Min.   :-189   Min.   : 0.000   Min.   :0  
 1st Qu.: 5.000   1st Qu.:124.0   1st Qu.:  16   1st Qu.: 0.000   1st Qu.:0  
 Median : 9.000   Median :159.0   Median :  47   Median : 3.000   Median :0  
 Mean   : 9.986   Mean   :160.2   Mean   :  50   Mean   : 7.608   Mean   :0  
 3rd Qu.:14.000   3rd Qu.:194.0   3rd Qu.:  81   3rd Qu.:12.000   3rd Qu.:0  
 Max.   :26.000   Max.   :368.0   Max.   : 243   Max.   :57.000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :36.85   Min.   :-5.7333   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.30   1st Qu.:-1.8853   1st Qu.:  69.0  
 Median :  0.0000   Median :41.19   Median : 0.5356   Median : 427.0  
 Mean   :  0.1599   Mean   :40.87   Mean   :-0.2711   Mean   : 458.5  
 3rd Qu.:  0.0000   3rd Qu.:41.84   3rd Qu.: 1.6331   3rd Qu.: 785.0  
 Max.   :458.0000   Max.   :43.36   Max.   : 4.2156   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt          tmax              tmin             precip      
 Min.   : 1.00   Min.   :-109.00   Min.   :-175.00   Min.   :  0.00  
 1st Qu.:14.00   1st Qu.:  28.00   1st Qu.: -34.00   1st Qu.:  4.00  
 Median :27.00   Median :  78.00   Median :  10.00   Median : 20.00  
 Mean   :26.56   Mean   :  83.96   Mean   :  13.55   Mean   : 32.89  
 3rd Qu.:39.00   3rd Qu.: 139.00   3rd Qu.:  64.00   3rd Qu.: 50.00  
 Max.   :53.00   Max.   : 299.00   Max.   : 183.00   Max.   :200.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.29   1st Qu.:  0.7789  
 Median :0   Median :   0.000   Median :42.47   Median :  1.0544  
 Mean   :0   Mean   :   8.264   Mean   :42.27   Mean   :  0.7201  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.7150  
 Max.   :0   Max.   :1073.000   Max.   :42.77   Max.   :  2.4378  
    altitud    
 Min.   :1097  
 1st Qu.:1971  
 Median :2247  
 Mean   :2204  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.00   Min.   :193.0   Min.   :0  
 1st Qu.:10.00   1st Qu.:102.0   1st Qu.:  42.00   1st Qu.:233.0   1st Qu.:0  
 Median :40.00   Median :139.0   Median :  80.50   Median :256.5   Median :0  
 Mean   :29.92   Mean   :135.9   Mean   :  73.51   Mean   :282.0   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:182.2   3rd Qu.: 117.00   3rd Qu.:309.2   3rd Qu.:0  
 Max.   :53.00   Max.   :331.0   Max.   : 217.00   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.742   1st Qu.:  66.7  
 Median :  0.000   Median :42.12   Median : -1.033   Median : 261.0  
 Mean   :  5.531   Mean   :40.78   Mean   : -2.630   Mean   : 696.9  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.168   3rd Qu.:1055.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBzZW1hbmEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiAxNTMKKiBEZXNjcmlwY2nDs246IAoqIEZyZWN1ZW5jaWE6IHNlbWFuYQoqIFZhcmlhYmxlczogZmVjaGFfY250LCBwcmVjaXAsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkCiogRGltZW5zaW9uZXMgZGVsIG1hcGE6IDUsNQoqIEl0ZXJhY2lvbmVzOiAxMDAwCiogUGFyw6FtZXRyb3MgYWRpY2lvbmFsZXM6IAoKYGBge3J9CnNvdXJjZSgiLi4vLi4vbGliL3NvbS11dGlscy5SIikKc291cmNlKCIuLi8uLi9saWIvbWFwcy11dGlscy5SIikKYGBgCgojIENhcmdhIGRlbCBtb2RlbG8gZGVzZGUgZGlzY28KCmBgYHtyfQptcHIuc2V0X2Jhc2VfcGF0aF9hbmFseXNpcygpCm1vZGVsIDwtIG1wci5sb2FkX21vZGVsKCJzb20tMTUzLnJkcy54eiIpCnN1bW1hcnkobW9kZWwpCmBgYAoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImNoYW5nZXMiKQpgYGAKCiMgQ2FyZ2EgZGVsIGRhdGFzZXQgZGUgZW50cmFkYQoKYGBge3J9CmRmIDwtIG1wci5sb2FkX2RhdGEoImRhdG9zX3NlbWFuYV8yay5jc3YueHoiKQpgYGAKCmBgYHtyfQpkZgpgYGAKCmBgYHtyfQpzdW1tYXJ5KGRmKQpgYGAKCiMgQ2FyZ2EgZGUgbG9zIG1hcGFzCgpgYGB7cn0Kd29ybGQgPC0gbmVfY291bnRyaWVzKHNjYWxlID0gIm1lZGl1bSIsIHJldHVybmNsYXNzID0gInNmIikKc3BhaW4gPC0gc3Vic2V0KHdvcmxkLCBhZG1pbiA9PSAiU3BhaW4iKQpgYGAKCiMgTWFwYSBkZSBkZW5zaWRhZAoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImNvdW50Iiwgc2hhcGUgPSAic3RyYWlnaHQiLCBwYWxldHRlLm5hbWUgPSBtcHIuZGVncmFkZS5ibGV1KQpgYGAKCk7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2VsZGE6CgpgYGB7cn0KbmIgPC0gdGFibGUobW9kZWwkdW5pdC5jbGFzc2lmKQpwcmludChuYikKYGBgCkNvbXByb2JhY2nDs24gZGUgbm9kb3MgdmFjw61vczoKCmBgYHtyfQpkaW1fbW9kZWwgPC0gNSo1OwpsZW5fbmIgPSBsZW5ndGgobmIpOwplbXB0eV9ub2RlcyA8LSBkaW1fbW9kZWwgIT0gbGVuX25iOwppZiAoZW1wdHlfbm9kZXMpIHsKICBwcmludChwYXN0ZSgiW1dhcm5pbmddIEV4aXN0ZW4gbm9kb3MgdmFjw61vczogIiwgbGVuX25iLCAiLyIsIGRpbV9tb2RlbCkpCn0KYGBgCgojIE1hcGEgZGUgZGlzdGFuY2lhIGVudHJlIHZlY2lub3MKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJkaXN0Lm5laWdoYm91cnMiLCBzaGFwZSA9ICJzdHJhaWdodCIpCmBgYAoKIyBJbmZsdWVuY2lhIGRlIGxhcyB2YXJpYWJsZXMKCmBgYHtyfQptb2RlbF9jb2xuYW1lcyA9IGMoImZlY2hhX2NudCIsICJwcmVjaXAiLCAibG9uZ2l0dWQiLCAibGF0aXR1ZCIsICJhbHRpdHVkIikKbW9kZWxfbmNvbCA9IGxlbmd0aChtb2RlbF9jb2xuYW1lcykKYGBgCgojIyBNYXBhIGRlIHZhcmlhYmxlcy4KCmBgYHtyfQpwbG90KG1vZGVsLCBzaGFwZSA9ICJzdHJhaWdodCIpCmBgYAoKIyMgTWFwYSBkZSBjYWxvciBwb3IgdmFyaWFibGUKCmBgYHtyfQpwYXIobWZyb3c9YygzLDQpKQpmb3IgKGogaW4gMTptb2RlbF9uY29sKSB7CiAgcGxvdChtb2RlbCwgdHlwZT0icHJvcGVydHkiLCBwcm9wZXJ0eT1nZXRDb2Rlcyhtb2RlbCwxKVssal0sCiAgICBwYWxldHRlLm5hbWU9bXByLmNvb2xCbHVlSG90UmVkLAogICAgbWFpbj1tb2RlbF9jb2xuYW1lc1tqXSwKICAgIGNleD0wLjUsIHNoYXBlID0gInN0cmFpZ2h0IikKfQpgYGAKCiMjIENvcnJlbGFjacOzbiBwYXJhIGNhZGEgY29sdW1uYSBkZWwgdmVjdG9yIGRlIG5vZG9zCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGNvciA8LSBhcHBseShnZXRDb2Rlcyhtb2RlbCwxKSwgMiwgbXByLndlaWdodGVkLmNvcnJlbGF0aW9uLCB3PW5iLCBzb209bW9kZWwpCiAgcHJpbnQoY29yKQp9CmBgYAoKUmVwcmVzZW50YWNpw7NuIGRlIGNhZGEgdmFyaWFibGUgZW4gdW4gbWFwYSBkZSBmYWN0b3JlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGFyKG1mcm93PWMoMSwxKSkKICBwbG90KGNvclsxLF0sIGNvclsyLF0sIHhsaW09YygtMSwxKSwgeWxpbT1jKC0xLDEpLCB0eXBlPSJuIikKICBsaW5lcyhjKC0xLDEpLGMoMCwwKSkKICBsaW5lcyhjKDAsMCksYygtMSwxKSkKICB0ZXh0KGNvclsxLF0sIGNvclsyLF0sIGxhYmVscz1tb2RlbF9jb2xuYW1lcywgY2V4PTAuNzUpCiAgc3ltYm9scygwLDAsY2lyY2xlcz0xLGluY2hlcz1GLGFkZD1UKQp9CmBgYAoKSW1wb3J0YW5jaWEgZGUgY2FkYSB2YXJpYWJsZSAtIHZhcmlhbnphIHBvbmRlcmFkYSBwb3IgZWwgdGFtYcOxbyBkZSBsYSBjZWxkYToKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgc2lnbWEyIDwtIHNxcnQoYXBwbHkoZ2V0Q29kZXMobW9kZWwsMSksMixmdW5jdGlvbih4LGVmZmVjdGlmKQogICAgIHttPC1zdW0oZWZmZWN0aWYqKHgtd2VpZ2h0ZWQubWVhbih4LGVmZmVjdGlmKSleMikvKHN1bShlZmZlY3RpZiktMSl9LAogICAgIGVmZmVjdGlmPW5iKSkKICBwcmludChzb3J0KHNpZ21hMixkZWNyZWFzaW5nPVQpKQp9CmBgYAoKIyBDbHVzdGVyaW5nCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGhhYyA8LSBtcHIuaGFjKG1vZGVsLCBuYikKfQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDMgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz0zKQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9MykKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA0IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTQpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDUgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz01KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NSkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDYgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz02KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NikKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSwgZGltKGRmLmNsdXN0ZXIwNilbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCiAgZGYuY2x1c3RlcjA2Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDYpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDYuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA4IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9OCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTgpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKICBkZi5jbHVzdGVyMDcgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT03KQogIGRmLmNsdXN0ZXIwOCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTgpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA3IDwtIHNlbGVjdChkZi5jbHVzdGVyMDcsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA4LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDgpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSwgZGltKGRmLmNsdXN0ZXIwNilbMV0sIGRpbShkZi5jbHVzdGVyMDcpWzFdLCBkaW0oZGYuY2x1c3RlcjA4KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiwgImNsdXN0ZXIwNyIsICJjbHVzdGVyMDgiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDgpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCiAgZGYuY2x1c3RlcjA2Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDYpCiAgZGYuY2x1c3RlcjA3Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDcpCiAgZGYuY2x1c3RlcjA4Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDgpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDYuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDcuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDguZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSAxMCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTEwKQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9MTApCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKICBkZi5jbHVzdGVyMDcgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT03KQogIGRmLmNsdXN0ZXIwOCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTgpCiAgZGYuY2x1c3RlcjA5IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OSkKICBkZi5jbHVzdGVyMTAgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xMCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDcgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA4IDwtIHNlbGVjdChkZi5jbHVzdGVyMDgsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA5LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMTAgPC0gc2VsZWN0KGRmLmNsdXN0ZXIxMCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA4KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMTApCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSwgZGltKGRmLmNsdXN0ZXIwNilbMV0sIGRpbShkZi5jbHVzdGVyMDcpWzFdLCBkaW0oZGYuY2x1c3RlcjA4KVsxXSwgZGltKGRmLmNsdXN0ZXIwOSlbMV0sIGRpbShkZi5jbHVzdGVyMTApWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiLCAiY2x1c3RlcjA3IiwgImNsdXN0ZXIwOCIsICJjbHVzdGVyMDkiLCAiY2x1c3RlcjEwIiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA4KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIxMCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA4KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIxMCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCiAgZGYuY2x1c3RlcjA2Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDYpCiAgZGYuY2x1c3RlcjA3Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDcpCiAgZGYuY2x1c3RlcjA4Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDgpCiAgZGYuY2x1c3RlcjA5Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDkpCiAgZGYuY2x1c3RlcjEwLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMTApCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDYuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDcuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDguZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDkuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMTAuZ3JvdXBlZCkKYGBgCg==